#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <unistd.h>
#include <functional>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <pthread.h>
#include "inetAddr.hpp"
#include "threadpool.hpp"
#include "LockGuard.hpp"
using task_t = std::function<void()>;
class Route //消息转发类
{
    public:
        Route()
        {
            pthread_mutex_init(&_mutex, nullptr);
        }
        void CheckOnlineUser(InetAddr& who) //检查用户列表
        {
            LockGuard lockguard(&_mutex); //访问临界资源加锁
            for(auto& user : _online_user)
            {
                if(who == user)
                {    
                    Log(DEBUG, "%s is exists\n", who.AddrStr().c_str());
                    return;
                }
            }
            Log(DEBUG, "%s is not exists, add it\n", who.AddrStr().c_str());
            _online_user.push_back(who);
        }
        void Offline(InetAddr& who) //给用户下线，从用户在线列表移除
        {
            LockGuard lockguard(&_mutex); //访问临界资源加锁
            auto iter = _online_user.begin();
            while(iter != _online_user.end())
            {
                
                if(*iter == who)
                {
                    Log(DEBUG, "%s is offline\n", who.AddrStr().c_str());
                    _online_user.erase(iter);
                    break;
                }
                iter++;
            }
        }
        void ForwordHelper(int sockfd, const std::string message, InetAddr& who) //将消息转发给所有用户
        {
            LockGuard lockguard(&_mutex); //访问临界资源加锁
            std::string send_message = "[" + who.AddrStr() + "]# " + message; //[ip:port]# message
            for(auto& user : _online_user) //遍历所有在线用户
            {
                Log(DEBUG, "Forword message to: %s, message is: %s\n", user.AddrStr().c_str(), message.c_str());
                struct sockaddr_in peer = user.Addr(); //接收到用户相关信息
                ::sendto(sockfd, send_message.c_str(), send_message.size(), 0, (struct sockaddr*)&peer, sizeof peer); //将消息转发给对应用户
            }
        }
        void Forword(int sockfd, const std::string& message, InetAddr& who) //消息转发
        {
            CheckOnlineUser(who); //检查用户列表，如果在列表中什么都不做，如果没有则尾插到列表
            if(message == "QUIT" || message == "Q") //如果用户发送这两条消息，表示用户想下线，
            {
                Offline(who); //从用户在线列表移除
            }
            //ForwordHelper(sockfd, message); //将消息转发给所有用户
            task_t t = std::bind(&Route::ForwordHelper, this, sockfd, message, who); //转发任务绑定，方便交给线程池
            ThreadPool<task_t>::GetInstanse()->Equeue(t); //将转发任务增加到任务队列中进行多线程处理
        }
        ~Route()
        {
            pthread_mutex_destroy(&_mutex);
        }
    private:
        std::vector<InetAddr> _online_user; //用户在线列表
        pthread_mutex_t _mutex; //访问用户列表临界资源要加锁
};